package mygame.hudelements;

import com.jme3.asset.AssetManager;
import com.jme3.export.Savable;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial;
import com.jme3.scene.control.Control;
import com.jme3.ui.Picture;
import mygame.Main;
import mygame.PlaneBasicControl;

/**
 *
 * @author Aicher
 */
public class AltOverGroundControl extends InstrumentControl implements Savable, Cloneable{
    /**
     * The instrumend frame is derived by this image
     */    
    public static final String IMG_ALTOVERGROUND_INSTRUMENT = "IMG_AltOverGround_Instrument";
    
    /**
     * Name of the segment elements. They are named according the position
     * and the segment id: IMG_Altoverground_Segment_P_ID
     */
    public static final String IMG_SEGMENT = "IMG_AltOverGround_Segement_";
    
    /**
     * Array position of the x coordinate info
     */
    public static final int X_POS = 0;
    
    /**
     * Array position of the y coordinate info
     */
    public static final int Y_POS = 1;
    
    /**
     * Location of all segments (relative to the lower left point)
     */
    private static final int[][] SEGMENT_POS = {
        {8,88},
        {8,44},
        {8,0},
        {0,50},
        {45,50},
        {0,7},
        {45,7}
    };

    /**
     * Matrix indicates, which segment should be shown for which digit
     */
    private static final boolean[][] SEGMENT_MATRIX = {
        //0       1      2     3     4      5       6
        {true , false, true , true , true , true , true },// 0
        {false, false, false, false, true , false, true },// 1
        {true , true , true , false, true , true , false},// 2
        {true , true , true , false, true , false, true },// 3
        {false, true , false, true , true , false, true },// 4
        {true , true , true , true , false, false, true },// 5
        {true , true , true , true , false, true , true },// 6
        {true , false, false, false, true , false, true },// 7
        {true , true , true , true , true , true , true },// 8
        {true , true , true , true , true , false, true}  // 9
    };
    
    /**
     * All segment elements to show (5 digits, each with 7 segments)
     */
    private Picture[][] segmentElements = new Picture[5][7];

    /**
     * height over ground in feet
     */
    private int heightOverGroundFeet = 0;
    
    /**
     * Digit position of the number to show
     */
    private int digitValue = 0;
    
    /**
     * Currently extracted digit to display
     */
    private int currentDigitValue = 0;
    
    /**
     * Constructor
     * @param guiNode Reference to the guiNode
     * @param assetManager For loading the images
     * @param instrumentLeftGridPosX position of the left border (in grid size measures)
     * @param instrumentLowerGridPos position of the lower border (in grid size measures)Y
     * @param hudReferenceSize Sise of one grid measure
     * @param instrumentGridWidth Width of the instrument in grid measures
     * @param instrumentGridHeight  Height of the instrument in grid measures
     * @param screenHeight  Height of the screen in pixel
     * @param measureFromBottom Set to true, if the LowerGridPos should be measured from 
     * the bottom. Set it to fals in order to measure it from the top
     */
    public AltOverGroundControl (Node guiNode,
            AssetManager assetManager,
            float instrumentLeftGridPosX,
            float instrumentLowerGridPosY,
            float hudReferenceSize,
            float instrumentGridWidth,
            float instrumentGridHeight,
            int screenHeight,
            boolean measureFromBottom,
            float minimalCalculationLoopTime
            ) {
        super(guiNode, assetManager,
                instrumentLeftGridPosX,
                instrumentLowerGridPosY,
                hudReferenceSize,
                instrumentGridWidth,
                instrumentGridHeight,
                screenHeight,
                measureFromBottom,
                minimalCalculationLoopTime);
        this.initAltOverGround();
    }    
    
    /**
     * Does all initialisation tasks
     */
    private void initAltOverGround() {
        // creates the instrument panel image
        this.centralInstrumentNode.attachChild(
                this.createInstrumentElementAbsolute(IMG_ALTOVERGROUND_INSTRUMENT, 
                "Textures/altoverground/altoverground_instrument.png"));
        
        // pixelReference is the size of a pixel as a fraction of the displayed pixel
        float pixelReference = this.instrumentWidth / 700.0f;

        // now calculate the (real) pixel width of a single digit field. This is needed
        // for positioning the 5 digit elements
        float digitWidth = 83 * pixelReference;
        
        // the most right digit position - this is the starting point of the digit
        // positioning
        float rightPoint = 438 * pixelReference;
        
        // Calculate the position of the lower point of the digits
        float lowerDigitPoint = 18 * pixelReference;
        
        // The segment length and width (of a horizontal segment) is calculated.
        // For a vertical segment width and length are swapped
        float segmentLength = 42 * pixelReference;
        float segmentWidth = 14 * pixelReference;

        // now all segment images are created and positioned. The following concept was choosen:
        //  -0-
        // |   |
        // 3   4
        // |   |
        //  -1-
        // |   |
        // 5   6
        // |   |
        //  -2-        
        for (int i = 0; i < this.segmentElements.length; i++) {
            for (int j = 0; j < this.segmentElements[i].length; j++) {
                this.segmentElements[i][j] = new Picture(IMG_SEGMENT + i + "_" + j);
                // The lower three segments are horizontal, all others are vertical
                if (j < 3) {
                    this.segmentElements[i][j].setImage(assetManager, 
                            "Textures/altoverground/segment_h.png", true);
                    this.segmentElements[i][j].setWidth(segmentLength);
                    this.segmentElements[i][j].setHeight(segmentWidth);
                } else {
                    this.segmentElements[i][j].setImage(assetManager, 
                            "Textures/altoverground/segment_v.png", true);
                    this.segmentElements[i][j].setWidth(segmentWidth);
                    this.segmentElements[i][j].setHeight(segmentLength);
                }
                // place the segment according to the istrument position,
                // the most right point, the digit width in combination with the
                // digit id 0-5
                this.segmentElements[i][j].setLocalTranslation(
                        this.instrumentLeftPosX + rightPoint - (i * digitWidth) +
                        SEGMENT_POS[j][X_POS] * pixelReference,
                        this.instrumentLowerPosY + lowerDigitPoint + 
                        SEGMENT_POS[j][Y_POS] * pixelReference, 0
                        );
                this.centralInstrumentNode.attachChild(this.segmentElements[i][j]);
            }
        }
        this.guiNode.attachChild(this.centralInstrumentNode);
    }
    
    /**
     * This method gets the height over ground from the PlaneBasicControl and converts it to
     * a value in feet. Then the five digit values are calculated and the segemnt are switched
     * on/off accordingly
     */
    private void updateNumbers() {
        this.heightOverGroundFeet = (int)(((PlaneBasicControl)spatial.getControl(PlaneBasicControl.class))
                .heightOverGround * Main.COORD_IN_FEET_FACTOR);
        
        // The first digit will be most right one (multiples of 1)
        this.digitValue = 1;
        
        // now care for all digits by looping through the first dimension of the array
        for (int i = 0; i < this.segmentElements.length; i++) {
            
            // calculate the value on the position of the current digit value (meaning
            // cutting all left values off)
            this.currentDigitValue = this.heightOverGroundFeet / this.digitValue;
            
            // Now the right values are cut off -> so a number between 0 and 9 remains
            this.currentDigitValue %= 10;
            
            // now check if the plane is not below ground. This check is necessary, because
            // we directly access an array in order to get the right segement elements for 
            // the number in the current digit value
            if (this.currentDigitValue >= 0) {
                // Now the segments are switched on / off according to the SEGMENT_MATRIX array
                for (int j = 0; j < this.segmentElements[i].length; j++) {
                    if (SEGMENT_MATRIX[this.currentDigitValue][j]) {
                        this.segmentElements[i][j].setCullHint(Spatial.CullHint.Inherit);
                    } else {
                        this.segmentElements[i][j].setCullHint(Spatial.CullHint.Always);
                    }
                }
            }
            this.digitValue *= 10;
        }
    }
    
    @Override
    protected void controlUpdate(float tpf) {
        this.timeSinceLastUpdate += tpf;
        if (this.timeSinceLastUpdate > this.minimalCalculationLoopTime) {
            this.updateNumbers();
        }
    }

    @Override
    protected void controlRender(RenderManager rm, ViewPort vp) {
        // not needed yet
    }
    
    @Override
    public Control cloneForSpatial(Spatial theSpatial) {
        final AltOverGroundControl control = new AltOverGroundControl(
                guiNode, 
                assetManager,
                instrumentLeftGridPosX,
                instrumentLowerGridPosY,
                hudReferenceSize,
                instrumentGridWidth,
                instrumentGridHeight,
                screenHeight,
                measureFromBottom,
                minimalCalculationLoopTime);
        
        control.setSpatial(spatial);
        return control;
    }
    
}
